<?php
interface Service
{
    /** @return string */
    public function getName();
    public function execute();
}
class ServiceA implements Service
{
    public function getName()
    {
        return "ServiceA";
    }
    public function execute()
    {
        echo "Executing Service A\r\n";
    }
}
class ServiceB implements Service
{
    public function getName()
    {
        return "ServiceB";
    }
    public function execute()
    {
        echo "Executing Service B\r\n";
    }
}
class InitialContext
{
    /** @return Service */
    public function lookup($jndiName)
    {
        $jndiName = strtolower($jndiName);
        if($jndiName === strtolower("ServiceA")){
            echo "Looking up and creating a new ServiceA object\r\n";
            return new ServiceA();
        }
        elseif($jndiName === strtolower("ServiceB")){
            echo "Looking up and creating a new ServiceB object\r\n";
            return new ServiceB();
        }
        return null;
    }
}
class Cache
{
    /** @var Service[] $services */
    protected $services;
    public function __construct()
    {
        $this->services = [];
    }
    /** @return Service */
    public function getService($serviceName)
    {
        $serviceName = strtolower($serviceName);
        foreach($this->services as $service){
            if(strtolower($service->getName()) === $serviceName){
                echo "Returning cached {$service->getName()} object\r\n";
                return $service;
            }
        }
        return null;
    }
    /** @param Service $newService */
    public function addService($newService)
    {
        if(!in_array($newService, $this->services)) $this->services[] = $newService;
    }
}
class ServiceLocator
{
    /** @var Cache $cache */
    private static $cache;
    /** @return Service */
    public static function getService($jndiName){
        if(!self::$cache) self::$cache = new Cache;
        if($service = self::$cache->getService($jndiName)) return $service;
        $context = new InitialContext();
        $service = $context->lookup($jndiName);
        self::$cache->addService($service);
        return $service;
    }
}

header('Content-Type: text/plain');

$service = ServiceLocator::getService("ServiceA");
$service->execute();
$service = ServiceLocator::getService("ServiceB");
$service->execute();
$service = ServiceLocator::getService("ServiceA");
$service->execute();
$service = ServiceLocator::getService("ServiceB");
$service->execute();
